Generated Types
This page documents what type definitions in TypeSpec are generated as in emitted libraries
Models​
Flattening​
NOTE: Flattening is NOT a recommended pattern, and you shouldn't use it unless told by SDK architects.
- TypeSpec
- TCGC
- Python
- CSharp
- Typescript
- Java
model Properties {
name: string;
}
model Foo {
@flattenProperty
prop: Properties;
}
{
"kind": "model",
"name": "Foo",
"properties": [
{
"kind": "property",
"name": "prop",
"serializedName": "prop",
"flatten": true,
"optional": false,
"type": {
"kind": "model",
"name": "Properties",
"properties": [
{
"kind": "property",
"name": "name",
"serializedName": "name",
"flatten": false,
"optional": false,
"type": {
"kind": "string",
"encode": "string"
}
}
]
}
}
]
}
Python will do dynamic flattening, exposing the non-flattening syntax, and dynamically accepting the flattened access.
class Properties(_model_base.Model):
name: str = rest_field()
"""Required."""
class Foo(_model_base.Model):
properties: "_models.Properties" = rest_field()
"""Required."""
__flattened_items = ["properties"]
print(f.properties.name) # Non-flattened access is preferred experience
print(f.name) # Flattened access is dynamically supported, but not documented
CSharp will generate the model with properties being flattened. During serialization/deserialization, the model will be serialized/deserialized as a non-flattened model.
public partial class Foo
{
public Foo(string name)
{
Argument.AssertNotNull(name, nameof(name));
Name = name;
}
public string Name { get; set; }
}
public partial class Foo : IUtf8JsonSerializable, IJsonModel<Foo>
{
void IJsonModel<Foo>.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options)
{
var format = options.Format == "W" ? ((IPersistableModel<Foo>)this).GetFormatFromOptions(options) : options.Format;
if (format != "J")
{
throw new FormatException($"The model {nameof(Foo)} does not support writing '{format}' format.");
}
writer.WriteStartObject();
writer.WritePropertyName("properties"u8);
writer.WriteStartObject();
writer.WritePropertyName("name"u8);
writer.WriteStringValue(Name);
writer.WriteEndObject();
writer.WriteEndObject();
}
internal static Foo DeserializeFoo(JsonElement element, ModelReaderWriterOptions options = null)
{
options ??= ModelSerializationExtensions.WireOptions;
if (element.ValueKind == JsonValueKind.Null)
{
return null;
}
string name = default;
foreach (var property in element.EnumerateObject())
{
if (property.NameEquals("properties"u8))
{
if (property.Value.ValueKind == JsonValueKind.Null)
{
property.ThrowNonNullablePropertyIsNull();
continue;
}
foreach (var property0 in property.Value.EnumerateObject())
{
if (property0.NameEquals("name"u8))
{
name = property0.Value.GetString();
}
}
}
}
return new Foo(name);
}
}
// Please note that this feature is not supported right now, and the model will be generated un-flattened.
// Please comment and follow work status on: https://github.com/Azure/autorest.typescript/issues/2164
In Java, @flattenProperty
have no effect on generated libraries.
@Fluent
public final class Properties {
public Properties();
public String getName();
public Properties setName(String name);
}
Models with additional properties​
Additional properties of any type​
- TypeSpec
- TCGC
- Python
- CSharp
- Typescript
- Java
Recommend usage:
model Animal {
name: string;
kind: string;
...Record<unknown>;
}
Other usages:
model Animal extends Record<unknown> {
name: string;
kind: string;
}
model Animal is Record<unknown> {
name: string;
kind: string;
}
{
"kind": "model",
"name": "Animal",
"properties": [
{
"kind": "property",
"name": "name",
"serializedName": "name",
"optional": false,
"type": {
"kind": "string",
"encode": "string"
}
},
{
"kind": "property",
"name": "kind",
"serializedName": "kind",
"optional": false,
"type": {
"kind": "string",
"encode": "string"
}
}
],
"additionalProperties": {
"kind": "any"
}
}
Python models are designed to support adding any additional properties.
from .. import _model_base
from .._model_base import rest_field
class Animal(_model_base.Model):
name: str = rest_field()
kind: str = rest_field()
animal = Animal(name="Tom", kind="Cat")
animal["friend"] = "Jerry"
animal["age"] = 5
public partial class Animal : IJsonModel<Animal> {
public Animal(string name, string kind);
public string Name { get; }
public string Kind { get; }
public IDictionary<string, BinaryData> AdditionalProperties { get; }
}
// RLC input
export interface Animal extends Record<string, unknown> {
name: string;
kind: string;
}
// RLC output
export interface AnimalOutput extends Record<string, any> {
name: string;
kind: string;
}
// Modular for both legacy and non legacy
export interface Animal extends Record<string, any> {
name: string;
kind: string;
}
@Fluent
public final class Animal implements JsonSerializable<Animal> {
public Animal(String name, String kind);
public String getName();
public String getKind();
public Map<String, Object> getAdditionalProperties();
public Animal setAdditionalProperties(Map<String, Object> additionalProperties);
}
Additional properties of specific type​
- TypeSpec
- TCGC
- Python
- CSharp
- Typescript
- Java
model AnimalProperty {
category: string;
value: unknown;
}
model Animal {
name: string;
kind: string;
...Record<AnimalProperty>;
}
{
"kind": "model",
"name": "Animal",
"properties": [
{
"kind": "property",
"name": "name",
"serializedName": "name",
"optional": false,
"type": {
"kind": "string",
"encode": "string"
}
},
{
"kind": "property",
"name": "kind",
"serializedName": "kind",
"optional": false,
"type": {
"kind": "string",
"encode": "string"
}
}
],
"additionalProperties": {
"kind": "model",
"name": "AnimalProperty",
"properties": [
{
"kind": "property",
"name": "category",
"serializedName": "category",
"optional": false,
"type": {
"kind": "string",
"encode": "string"
}
},
{
"kind": "property",
"name": "value",
"serializedName": "value",
"optional": false,
"type": {
"kind": "any"
}
}
],
"additionalProperties": undefined
}
}
Python models are designed to support adding any additional properties.
from typing import Any
from .. import _model_base
from .._model_base import rest_field
class Animal(_model_base.Model):
name: str = rest_field()
kind: str = rest_field()
class AnimalProperty(_model_base.Model):
category: str = rest_field()
value: Any = rest_field()
animal = Animal(name="Tom", kind="Cat")
animal["friend"] = AnimalProperty(category="relationship", value="Jerry")
animal["age"] = AnimalProperty(category="attribute", value=5)
Due to currently there is no way to know whether a Json could be correctly mapped into the specified type in .Net
, we currently generate any non-primitive value type in additional properties property as BinaryData
.
For typespec:
model Animal {
name: string;
kind: string;
...Record<AnimalProperty>;
}
The C#
generated code is the same as if the type is unknown
:
public partial class Animal : IJsonModel<Animal>
{
public Animal(string name, string kind);
public string Name { get; }
public string Kind { get; }
public IDictionary<string, BinaryData> AdditionalProperties { get; }
}
For typespec with additional properties of primitive types:
model Animal {
name: string;
kind: string;
...Record<string>;
}
The C#
generated code still has the specified type in AdditionalProperties
property:
public partial class Animal : IJsonModel<Animal>
{
public Animal(string name, string kind);
public string Name { get; }
public string Kind { get; }
public IDictionary<string, string> AdditionalProperties { get; }
}
// RLC input
export interface AnimalProperty {
category: string;
value: unknown;
}
export interface Animal extends Record<string, unknown> {
name: string;
kind: string;
}
// RLC output
export interface AnimalProperty {
category: string;
value: any;
}
export interface Animal extends Record<string, any> {
name: string;
kind: string;
}
// Modular for legacy clients
export interface AnimalProperty {
category: string;
value: any;
}
export interface Animal extends Record<string, any> {
name: string;
kind: string;
}
// Modular for non-legacy clients
export interface AnimalProperty {
category: string;
value: any;
}
export interface Animal {
name: string;
kind: string;
additionalProperties: Record<string, AnimalProperty>;
}
@Fluent
public final class Animal implements JsonSerializable<Animal> {
public Animal(String name, String kind);
public String getName();
public String getKind();
public Map<String, AnimalProperty> getAdditionalProperties();
public Animal setAdditionalProperties(Map<String, AnimalProperty> additionalProperties);
}
Additional properties of union type​
- TypeSpec
- TCGC
- Python
- CSharp
- Typescript
- Java
model Animal {
name: string;
kind: string;
...Record<string | int32>;
}
model Animal {
name: string;
kind: string;
...Record<string>;
...Record<int32>;
}
{
"kind": "model",
"name": "Animal",
"properties": [
{
"kind": "property",
"name": "name",
"serializedName": "name",
"optional": false,
"type": {
"kind": "string",
"encode": "string"
}
},
{
"kind": "property",
"name": "kind",
"serializedName": "kind",
"optional": false,
"type": {
"kind": "string",
"encode": "string"
}
}
],
"additionalProperties": {
"kind": "union",
"name": "AnimalAdditionalProperty",
"generatedName": true,
"values": [
{
"kind": "string",
"encode": "string"
},
{
"kind": "int32"
}
]
}
}
Python models are designed to support adding any additional properties.
from .. import _model_base
from .._model_base import rest_field
class Animal(_model_base.Model):
name: str = rest_field()
kind: str = rest_field()
animal = Animal(name="Tom", kind="Cat")
animal["friend"] = "Jerry"
animal["age"] = 5
public partial class Animal : IJsonModel<Animal>
{
public Animal(string name, string kind);
public string Name { get; }
public string Kind { get; }
public IDictionary<string, BinaryData> AdditionalProperties { get; }
}
// RLC input and output
export interface Animal extends Record<string, string | number> {
name: string;
kind: string;
}
// Modular for legacy and non-legacy clients
export interface Animal extends Record<string, string | number> {
name: string;
kind: string;
}
@Fluent
public final class Animal implements JsonSerializable<Animal> {
public Animal(String name, String kind);
public String getName();
public String getKind();
public Map<String, BinaryData> getAdditionalProperties();
public Animal setAdditionalProperties(Map<String, BinaryData> additionalProperties);
}
Additional properties of nullable type​
- TypeSpec
- TCGC
- Python
- CSharp
- Typescript
- Java
model Animal {
name: string;
kind: string;
...Record<string | null>;
}
{
"kind": "model",
"name": "Animal",
"properties": [
{
"kind": "property",
"name": "name",
"serializedName": "name",
"optional": false,
"type": {
"kind": "string",
"encode": "string"
}
},
{
"kind": "property",
"name": "kind",
"serializedName": "kind",
"optional": false,
"type": {
"kind": "string",
"encode": "string"
}
}
],
"additionalProperties": {
"kind": "nullable",
"valueType": {
"kind": "string",
"encode": "string"
}
}
}
Python models are designed to support adding any additional properties.
from .. import _model_base
from .._model_base import rest_field
class Animal(_model_base.Model):
name: str = rest_field()
kind: str = rest_field()
animal = Animal(name="Tom", kind="Cat")
animal["friend"] = "Jerry"
animal["alert"] = None
public partial class Animal : IJsonModel<Animal>
{
public Animal(string name, string kind);
public string Name { get; }
public string Kind { get; }
public IDictionary<string, string> AdditionalProperties { get; }
}
// RLC input and output
export interface Animal extends Record<string, string | null> {
name: string;
kind: string;
}
// Modular for legacy and non-legacy clients
export interface Animal extends Record<string, string | null> {
name: string;
kind: string;
}
@Fluent
public final class Animal implements JsonSerializable<Animal> {
public Animal(String name, String kind);
public String getName();
public String getKind();
public Map<String, String> getAdditionalProperties();
public Animal setAdditionalProperties(Map<String, String> additionalProperties);
}
Nullable​
TypeSpec uses | null
to represent nullable types. Nullability is handled differently in languages, but emitter authors will find information
about nullability by inspecting the type of a property.
- TypeSpec
- TCGC
- Python
- CSharp
- Typescript
- Java
model Foo {
basicNullableProperty: string | null;
modelNullableProperty: Bar | null;
unionNullableProperty: Bar | Baz | null;
enumNullableProperty: LR | null;
}
model Bar {
prop: string;
}
model Baz {
prop: int32;
}
enum LR {
left,
right,
}
A nullable type has kind nullable
and property valueType
. The kind of the type tells you the property is nullable, while the valueType
tells you the underlying type you want to generate.
{
"kind": "model",
"name": "Foo",
"properties": [
{
"kind": "property",
"name": "basicNullableProperty",
"serializedName": "basicNullableProperty",
"optional": false,
"type": {
"kind": "nullable",
"valueType": {
"kind": "string",
"encode": "string"
}
}
},
{
"kind": "property",
"name": "modelNullableProperty",
"serializedName": "modelNullableProperty",
"optional": false,
"type": {
"kind": "nullable",
"valueType": {
"kind": "model",
"name": "Bar",
"properties": [
{
"kind": "property",
"name": "prop",
"serializedName": "prop",
"optional": false,
"type": {
"kind": "string",
"encode": "string"
}
}
]
}
}
},
{
"kind": "property",
"name": "unionNullableProperty",
"serializedName": "unionNullableProperty",
"optional": false,
"type": {
"kind": "nullable",
"valueType": {
"kind": "union",
"values": [
{
"kind": "model",
"name": "Bar",
"properties": [
{
"kind": "property",
"name": "prop",
"serializedName": "prop",
"optional": false,
"type": {
"kind": "string",
"encode": "string"
}
}
]
},
{
"kind": "model",
"name": "Baz",
"properties": [
{
"kind": "property",
"name": "prop",
"serializedName": "prop",
"optional": false,
"type": {
"kind": "int32",
"encode": "int32"
}
}
]
}
]
}
}
},
{
"kind": "property",
"name": "enumNullableProperty",
"serializedName": "enumNullableProperty",
"optional": false,
"type": {
"kind": "nullable",
"valueType": {
"kind": "enum",
"name": "LR",
"generatedName": false,
"valueType": {
"kind": "string"
},
"values": [
{
"kind": "enumvalue",
"name": "left",
"value": "left"
},
{
"kind": "enumvalue",
"name": "right",
"value": "right"
}
],
"isFixed": true,
"isUnionAsEnum": false
}
}
}
]
}
Python treat nullable as optional. If you actually want to send the value null
to the service without the property being ignored, you can send in corehttp.serialization.NULL
. Python does not restrict you from setting any property to this value.
from enum import Enum
from corehttp.utils import CaseInsensitiveEnumMeta
class Bar(_model_base.Model):
prop: Optional[str] = rest_field()
class Baz(_model_base.Model):
prop: Optional[str] = rest_field()
class LR(str, Enum, metaclass=CaseInsensitiveEnumMeta):
LEFT = "left"
RIGHT = "right"
class Foo(_model_base.Model):
basicNullableProperty: Optional[str] = rest_field()
modelNullableProperty: Optional["_models.Bar"] = rest_field()
unionNullableProperty: Optional[Union["_models.Bar", "_models.Baz"]] = rest_field()
enumNullableProperty: Optional["LR"] = rest_field()
TODO
TODO
TODO
Unions​
Union of literals with same type​
All emitters will generate their version of a closed enum.
- TypeSpec
- TCGC
- Python
- CSharp
- Typescript
- Java
union LR {
left: "left",
right: "right",
}
{
"kind": "enum",
"name": "LR",
"generatedName": false,
"valueType": {
"kind": "string"
},
"values": [
{
"kind": "enumvalue",
"name": "left",
"value": "left"
},
{
"kind": "enumvalue",
"name": "right",
"value": "right"
}
],
"isFixed": true,
"isUnionAsEnum": true
}
Python never generates closed enum by design. We will always permit users to pass in additional values.
from enum import Enum
from corehttp.utils import CaseInsensitiveEnumMeta
class LR(str, Enum, metaclass=CaseInsensitiveEnumMeta):
LEFT = "left"
RIGHT = "right"
public enum LR
{
Left,
Right
}
Serialization/deserialization will respect the value defined, in this case it is "left" for LR.Left
and "right" for LR.Right
respectively.
export type LR = "left" | "right";
public enum LR {
LEFT("left"),
RIGHT("right");
}
Inline union of literals with same type​
This is union defined inline at point of usage.
- TypeSpec
- TCGC
- Python
- CSharp
- Typescript
- Java
model Widget {
horizontal: "left" | "right";
}
{
"kind": "enum",
"name": "WidgetHorizontals",
"generatedName": true,
"valueType": {
"kind": "string"
},
"values": [
{
"kind": "enumvalue",
"name": "left",
"value": "left"
},
{
"kind": "enumvalue",
"name": "right",
"value": "right"
}
],
"isFixed": true,
"isUnionAsEnum": true
}
Python generates this as a union of literals, not as enum. We also don't generate a closed set of literals.
from typing import Literal, Union
model Widget:
horizontal: Union[Literal["left"] | Literal["right"] | str]
public partial class Widget
{
public WidgetHorizontal Horizontal;
}
public enum WidgetHorizontal
{
Left,
Right
}
export interface Widget {
horizontal: "left" | "right";
}
public enum WidgetHorizontal {
LEFT("left"),
RIGHT("right");
}
Union of basic type and literals of that type​
Each language will generate their version of an open enum.
- TypeSpec
- TCGC
- Python
- CSharp
- Typescript
- Java
union Colors {
string,
red: "red",
blue: "blue",
}
{
"kind": "enum",
"name": "Colors",
"generatedName": false,
"valueType": {
"kind": "string"
},
"values": [
{
"kind": "enumvalue",
"name": "red",
"value": "red"
},
{
"kind": "enumvalue",
"name": "blue",
"value": "blue"
}
],
"isFixed": false,
"isUnionAsEnum": true
}
Python generates open enum again here.
from enum import Enum
from corehttp.utils import CaseInsensitiveEnumMeta
class Colors(str, Enum, metaclass=CaseInsensitiveEnumMeta):
RED = "red"
BLUE = "blue"
public readonly partial struct Colors : IEquatable<Colors>
{
private const string RedValue = "red";
private const string BlueValue = "blue";
public static Colors Red { get; } = new Colors(RedValue);
public static Colors Blue { get; } = new Colors(BlueValue);
}
export type Colors = string | "red" | "blue";
public final class Colors extends ExpandableStringEnum<Colors> {
public static final Colors RED = fromString("red");
public static final Colors BLUE = fromString("blue");
}
Inline union of basic type and literals of that type​
This is union defined inline at point of usage which include the base type as an option.
- TypeSpec
- TCGC
- Python
- CSharp
- Typescript
- Java
model Widget {
color: "red" | "blue" | string;
}
{
"kind": "enum",
"name": "WidgetColors",
"generatedName": true,
"valueType": {
"kind": "string"
},
"values": [
{
"kind": "enumvalue",
"name": "red",
"value": "red"
},
{
"kind": "enumvalue",
"name": "blue",
"value": "blue"
}
],
"isFixed": false,
"isUnionAsEnum": true
}
Python generates a union of literals again.
from typing import Literal, Union
model Widget:
color: Union[Literal["red"] | Literal["blue"] | str]
public partial class Widget
{
public WidgetColor Color;
}
public readonly partial struct WidgetColor : IEquatable<WidgetColor>
{
private const string RedValue = "red";
private const string BlueValue = "blue";
public static WidgetColor Red { get; } = new WidgetColor(RedValue);
public static WidgetColor Blue { get; } = new WidgetColor(BlueValue);
}
export interface Widget {
color: "red" | "blue" | string;
}
public final class WidgetColor extends ExpandableStringEnum<Colors> {
public static final Color RED = fromString("red");
public static final Color BLUE = fromString("blue");
}
Union of other union/enum, basic type and literals of that type​
- TypeSpec
- TCGC
- Python
- CSharp
- Typescript
- Java
import "@azure-tools/typespec-azure-resource-manager";
union ProvisioningState {
string,
"InProgress",
Azure.ResourceManager.ResourceProvisioningState,
}
For union of other union or enum. TCGC will do the flatten according to the flag.
With flatten-union-as-enum
flagged true
:
{
"kind": "enum",
"name": "ProvisioningState",
"generatedName": false,
"valueType": {
"kind": "string"
},
"values": [
{
"kind": "enumvalue",
"name": "InProgress",
"value": "InProgress"
},
{
"kind": "enumvalue",
"name": "Succeeded",
"value": "Succeeded"
},
{
"kind": "enumvalue",
"name": "Failed",
"value": "Failed"
},
{
"kind": "enumvalue",
"name": "Canceled",
"value": "Canceled"
}
],
"isFixed": false,
"isUnionAsEnum": true
}
With flatten-union-as-enum
flagged false
:
{
"kind": "union",
"name": "ProvisioningState",
"generatedName": false,
"values": [
{
"kind": "string"
},
{
"kind": "constant",
"value": "InProgress",
"valueType": {
"kind": "string"
}
},
{
"kind": "enum",
"name": "ResourceProvisioningState",
"generatedName": false,
"valueType": {
"kind": "string"
},
"values": [
{
"kind": "enumvalue",
"name": "Succeeded",
"value": "Succeeded"
},
{
"kind": "enumvalue",
"name": "Failed",
"value": "Failed"
},
{
"kind": "enumvalue",
"name": "Canceled",
"value": "Canceled"
}
],
"isFixed": true,
"isUnionAsEnum": false
}
]
}
Python generates a single open enum.
from enum import Enum
from corehttp.utils import CaseInsensitiveEnumMeta
class ProvisioningState(str, Enum, metaclass=CaseInsensitiveEnumMeta):
INPROGRESS = "InProgress"
SUCCEEDED = "Succeeded"
FAILED = "Failed"
CANCELED = "Canceled"
public readonly partial struct ProvisioningState : IEquatable<ProvisioningState>
{
private const string SucceededValue = "Succeeded";
private const string FailedValue = "Failed";
private const string CanceledValue = "Canceled";
private const string InProgressValue = "InProgress";
public static ProvisioningState Succeeded { get; } = new ProvisioningState(SucceededValue);
public static ProvisioningState Failed { get; } = new ProvisioningState(FailedValue);
public static ProvisioningState Canceled { get; } = new ProvisioningState(CanceledValue);
public static ProvisioningState InProgress { get; } = new ProvisioningState(InProgressValue);
}
export type ResourceProvisioningState = "Succeeded" | "Failed" | "Canceled";
// NOTE: extensible enum design may change in JS
export type ProvisioningState = string | "InProgress" | ResourceProvisioningState;
public final class ProvisioningState extends ExpandableStringEnum<ProvisioningState> {
public static final ProvisioningState INPROGRESS = fromString("InProgress");
public static final ProvisioningState SUCCEEDED = fromString("Succeeded");
public static final ProvisioningState FAILED = fromString("Failed");
public static final ProvisioningState CANCELED = fromString("Canceled");
}
Union of other unions of literals with same type​
- TypeSpec
- TCGC
- Python
- CSharp
- Typescript
- Java
union LR {
left: "left",
right: "right",
}
union UD {
up: "up",
down: "down",
}
union Orientation {
LR,
UD,
}
For union of other union or enum. TCGC will do the flatten according to the flag.
With flatten-union-as-enum
flagged true
:
{
"kind": "enum",
"name": "Orientation",
"generatedName": false,
"valueType": {
"kind": "string"
},
"values": [
{
"kind": "enumvalue",
"name": "left",
"value": "left"
},
{
"kind": "enumvalue",
"name": "right",
"value": "right"
},
{
"kind": "enumvalue",
"name": "up",
"value": "up"
},
{
"kind": "enumvalue",
"name": "down",
"value": "down"
}
],
"isFixed": true,
"isUnionAsEnum": true
}
With flatten-union-as-enum
flagged false
:
{
"kind": "union",
"name": "Orientation",
"generatedName": false,
"values": [
{
"kind": "enum",
"name": "LR",
"generatedName": false,
"valueType": {
"kind": "string"
},
"values": [
{
"kind": "enumvalue",
"name": "left",
"value": "left"
},
{
"kind": "enumvalue",
"name": "right",
"value": "right"
}
],
"isFixed": true,
"isUnionAsEnum": true
},
{
"kind": "enum",
"name": "UD",
"generatedName": false,
"valueType": {
"kind": "string"
},
"values": [
{
"kind": "enumvalue",
"name": "up",
"value": "up"
},
{
"kind": "enumvalue",
"name": "down",
"value": "down"
}
],
"isFixed": true,
"isUnionAsEnum": true
}
]
}
from enum import Enum
from corehttp.utils import CaseInsensitiveEnumMeta
class Orientation(str, Enum, metaclass=CaseInsensitiveEnumMeta):
LEFT = "left"
RIGHT = "right"
UP = "up"
DOWN = "down"
public enum Orientation
{
Left,
Right,
Up,
Down
}
export type LR = "left" | "right";
export type UD = "up" | "down";
export type Orientation = LR | UD;
public enum Orientation {
LEFT("left"),
RIGHT("right"),
UP("up"),
DOWN("down");
}
Inline union of other unions of literals with same type​
- TypeSpec
- TCGC
- Python
- CSharp
- Typescript
- Java
union LR {
left: "left",
right: "right",
}
union UD {
up: "up",
down: "down",
}
model Widget {
orientation: LR | UD;
}
For union of other union or enum. TCGC will do the flatten according to the flag.
With flatten-union-as-enum
flagged true
:
{
"kind": "enum",
"name": "WidgetOrientations",
"generatedName": true,
"valueType": {
"kind": "string"
},
"values": [
{
"kind": "enumvalue",
"name": "left",
"value": "left"
},
{
"kind": "enumvalue",
"name": "right",
"value": "right"
},
{
"kind": "enumvalue",
"name": "up",
"value": "up"
},
{
"kind": "enumvalue",
"name": "down",
"value": "down"
}
],
"isFixed": true,
"isUnionAsEnum": true
}
With flatten-union-as-enum
flagged false
:
{
"kind": "union",
"name": "WidgetOrientations",
"generatedName": true,
"values": [
{
"kind": "enum",
"name": "LR",
"generatedName": false,
"valueType": {
"kind": "string"
},
"values": [
{
"kind": "enumvalue",
"name": "left",
"value": "left"
},
{
"kind": "enumvalue",
"name": "right",
"value": "right"
}
],
"isFixed": true,
"isUnionAsEnum": true
},
{
"kind": "enum",
"name": "UD",
"generatedName": false,
"valueType": {
"kind": "string"
},
"values": [
{
"kind": "enumvalue",
"name": "up",
"value": "up"
},
{
"kind": "enumvalue",
"name": "down",
"value": "down"
}
],
"isFixed": true,
"isUnionAsEnum": true
}
]
}
Since this is inline, Python will generate this as a single union of all possible literal values.
from typing import Literal
type WidgetOrientation = "left" | "right" | "up" | "down" | str
model Widget:
orientation: WidgetOrientation
public partial class Widget
{
public WidgetOrientation Orientation;
}
public enum WidgetOrientation
{
Left,
Right,
Up,
Down
}
export interface Widget {
orientation: LR | UD;
}
export type LR = "left" | "right";
export type UD = "up" | "down";
public enum WidgetOrientation {
LEFT("left"),
RIGHT("right"),
UP("up"),
DOWN("down");
}
Union with multiple types​
These are unions where the values don't share same type.
- TypeSpec
- TCGC
- Python
- CSharp
- Typescript
- Java
model Shirt {
sizing: 32 | 34 | int32 | "small" | "medium" | string;
}
{
"kind": "union",
"name": "ShirtSizings",
"generatedName": true,
"values": [
{
"kind": "constant",
"value": 32,
"valueType": {
"kind": "int32"
}
},
{
"kind": "constant",
"value": 34,
"valueType": {
"kind": "int32"
}
},
{
"kind": "constant",
"value": "small",
"valueType": {
"kind": "string"
}
},
{
"kind": "constant",
"value": "medium",
"valueType": {
"kind": "string"
}
},
{
"kind": "string"
}
]
}
Python will generate this as a union since these entries don't share the same type
from typing import Literal
type ShirtSizing = Literal[32] | Literal[34] | int | Literal["small"] | Literal["medium"] | str
model Shirt:
sizing: ShirtSizing
public partial class Shirt
{
public BinaryData Shirt;
}
export interface Shirt {
sizing: 32 | 34 | number | "small" | "medium" | string;
}
public final class Shirt {
private BinaryData sizing;
}
Enums​
Standard​
Standard enums will be generated as closed enums.
- TypeSpec
- TCGC
- Python
- CSharp
- Typescript
- Java
enum LR {
left,
right,
}
{
"kind": "enum",
"name": "LR",
"generatedName": false,
"valueType": {
"kind": "string"
},
"values": [
{
"kind": "enumvalue",
"name": "left",
"value": "left"
},
{
"kind": "enumvalue",
"name": "right",
"value": "right"
}
],
"isFixed": true,
"isUnionAsEnum": false
}
Python never generates closed enums by design. We will always permit users to pass in additional values.
from enum import Enum
from corehttp.utils import CaseInsensitiveEnumMeta
class LR(str, Enum, metaclass=CaseInsensitiveEnumMeta):
LEFT = "left"
RIGHT = "right"
public enum LR
{
Left,
Right
}
export type LR = "left" | "right";
public enum LR {
LEFT("left"),
RIGHT("right");
}
Versioning Enums​
- TypeSpec
- TCGC
- Python
- CSharp
- Typescript
- Java
@versioned(Versions)
@service
namespace My.Service;
enum Versions {
v1,
v2,
}
{
"kind": "enum",
"name": "Versions",
"generatedName": false,
"valueType": {
"kind": "string"
},
"values": [
{
"kind": "enumvalue",
"name": "v1",
"value": "v1"
},
{
"kind": "enumvalue",
"name": "v2",
"value": "v2"
}
],
"isFixed": true,
"isUnionAsEnum": false,
"usage": 8
}
# Python does not generate the enum used for versioning
// CSharp does not generate the enum used for versioning
// JS does not generate the enum used for versioning
public enum ServiceServiceVersion implements ServiceVersion {
V1("v1"),
V2("v2");
}
Spread​
Spreading enums will return the resultant enum as a new single closed enum.
- TypeSpec
- TCGC
- Python
- CSharp
- Typescript
- Java
enum LR {
left,
right,
}
enum UD {
up,
down,
}
enum Orientation {
...LR,
...UD,
}
{
"kind": "enum",
"name": "Orientation",
"generatedName": false,
"valueType": {
"kind": "string"
},
"values": [
{
"kind": "enumvalue",
"name": "left",
"value": "left"
},
{
"kind": "enumvalue",
"name": "right",
"value": "right"
},
{
"kind": "enumvalue",
"name": "up",
"value": "up"
},
{
"kind": "enumvalue",
"name": "down",
"value": "down"
}
],
"isFixed": true,
"isUnionAsEnum": false
}
Python generates one open enum, because Python never generates an enum as fully closed.
from enum import Enum
from corehttp.utils import CaseInsensitiveEnumMeta
class Orientation(str, Enum, metaclass=CaseInsensitiveEnumMeta):
LEFT = "left"
RIGHT = "right"
UP = "up"
DOWN = "down"
public enum Orientation
{
Left,
Right,
Up,
Down
}
export type Orientation = "left" | "right" | "up" | "down";
public enum Orientation {
LEFT("left"),
RIGHT("right"),
UP("up"),
DOWN("down");
}
Scalars​
Encoding​
We will take the @encode
decorator into account, determining how we serialize inputted scalars to send over the wire.
- TypeSpec
- TCGC
- Python
- CSharp
- Typescript
- Java
model Test {
@encode(DateTimeKnownEncoding.rfc3339)
prop: utcDateTime;
}
{
"kind": "property",
"name": "prop",
"type": {
"kind": "utcDateTime",
"encode": "rfc3339",
"wireType": {
"kind": "string"
}
}
}
serialized_prop = json.dumps(prop, cls=SdkJSONEncoder, format="rfc3339")
TODO
TODO;
// Internal implementation
jsonWriter.writeStringField("prop",
this.value == null ? null : DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(this.value));
When you specify an encoding type, say that you want to encode an integer as a string, that will also be represented in our generated SDKs.
- TypeSpec
- TCGC
- Python
- CSharp
- Typescript
- Java
model Test {
@encode(string)
prop: int64;
}
{
"kind": "property",
"name": "prop",
"type": {
"kind": "int64",
"encode": "string",
"wireType": {
"kind": "string"
}
}
}
serialized_prop = json.dumps(prop, cls=SdkJSONEncoder, format="string")
TODO
TODO;
// Internal implementation
jsonWriter.writeStringField("prop", Objects.toString(this.value, null));